﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using System.Windows.Forms.DataVisualization.Charting.Utilities;
using System.Collections;
using Prob_Distributions_ClassLibrary;

namespace random_numbers
{
    public partial class Form1 : Form
    {

        //ATRIBUTOS 
        private RandomNumber rnd; //necesito declararlo acá para poder seguir generando números
        private List<double> lstRandoms; //la lista de números aleatorios generada, la utilizo para cargar la grilla
        private List<decimal> lstIntervals; //la lista de los intervalos que desean luego representar graficamente
        private List<int> lstFrecuency; //la lista de las frecuencias que desean luego representar graficamente
        private Boolean grafico = false;
        private Hashtable parametros;
        private decimal mayor;
        private decimal menor;
        private DistributionController dist;
        
        //CONSTRUCTOR
        public Form1()
        {
            InitializeComponent();
            inicializar();
            
        }
        private void inicializar()
        {
            //datos hardcodeados para testear + rápido
            txtSemilla.Text = "2917";
            txta.Text = "1664525";
            txtc.Text = "1013904223";
            txtm.Text = "4294967296";
            //chart_InFrec.Enabled = false;
            //chart_InFrec.Text = "Vacio Presione Generar Grafico";
        }

        //EVENTOS
       
        
        private void txt_Validating(object sender, CancelEventArgs e)
        {
            if (((System.Windows.Forms.TextBox)sender).Focused==true)
            {
                string error = validarNroEnteroPositivo(((System.Windows.Forms.TextBox)sender).Text) ? "" : "error tipo de dato";
                errorProvider1.SetError((System.Windows.Forms.TextBox)sender, error);
            }
        }


        //METODOS

        private void cargarGrilla()
        {
            dataGridView1.RowCount = lstRandoms.Count;

            for (int i = 0; i < lstRandoms.Count; i++)
            {
                dataGridView1.Rows[i].Cells["Orden"].Value = i.ToString();
                dataGridView1.Rows[i].Cells["nr"].Value = lstRandoms[i].ToString();
            }
        }

        private void cargarGrilla2()
        {
            dataGridView2.RowCount = lstIntervals.Count;
            //dataGridView2.Rows.Clear();
            for (int i = 0; i < lstIntervals.Count; i++)
            {
                if (i==0)
                    dataGridView2.Rows[i].Cells["col1_Rango"].Value = cmbDistribucion.SelectedIndex == (int)Utils.distribucion.Uniforme ? txt_lim_inf.Text + " - " + lstIntervals[i].ToString() : dist.getLimiteInferior().ToString() + " - " + lstIntervals[i].ToString();
                else
                    dataGridView2.Rows[i].Cells["col1_Rango"].Value = lstIntervals[i-1].ToString() + " - " + lstIntervals[i].ToString();                                
                dataGridView2.Rows[i].Cells["col2_Frec"].Value = lstFrecuency[i].ToString();
            }
        }
                
        //Metodo para validar que un string sea un nro entero positovo
        //usado en la validación de los parámetros
        private bool validarNroEnteroPositivo(string text)
        {
            double nr;
            if (double.TryParse(text, out nr))
            {
                if (nr >= 0)
                {
                    return true;
                }
                return false;
            }
            return false;
        }

        private bool validarParametros()
        {
            bool return_value = true;
            string error_entero_positivo= "Debe ser un valor numerico decimal positivo";
            if (!validarNroEnteroPositivo(txtCant.Text))
            {
                errorProvider1.SetError(txtCant, error_entero_positivo);
                return_value = false;
            }

            if (!validarNroEnteroPositivo(txtSemilla.Text))
            {
                errorProvider1.SetError(txtSemilla, error_entero_positivo);
                return_value = false;
            }

            if (!validarNroEnteroPositivo(txta.Text))
            {
                errorProvider1.SetError(txta, error_entero_positivo);
                return_value = false;
            }
            if (cmbMetodo.SelectedIndex == (int) Utils.metodo.Mixto)
            {
                if (!validarNroEnteroPositivo(txtc.Text))
                {
                    errorProvider1.SetError(txtc, error_entero_positivo);
                    return_value = false;
                }
            }
            if (!validarNroEnteroPositivo(txtm.Text))
            {
                errorProvider1.SetError(txtm, error_entero_positivo);
                return_value = false;
            }
            if (cmbDistribucion.SelectedIndex == -1)
            {
                lblFormula.Text = "ERROR SELECCIONE DIST";
                return false;
            }
            else
            {
                if (cmbDistribucion.SelectedIndex ==1  || cmbDistribucion.SelectedIndex == 2 || cmbDistribucion.SelectedIndex == 3)
                {
                    if (!validarNroEnteroPositivo(txt_lambda.Text))
                    {
                        errorProvider1.SetError(txt_lambda, error_entero_positivo);
                        return_value = false;
                    }
                }
                if (cmbDistribucion.SelectedIndex == 2)
                {
                    if (!validarNroEnteroPositivo(txt_desv.Text))
                    {
                        errorProvider1.SetError(txt_desv, error_entero_positivo);
                        return_value = false;
                    }
                }
                if (cmbDistribucion.SelectedIndex == 0)
                {
                    bool no_num = true;
                    if (!validarNroEnteroPositivo(txt_lim_inf.Text))
                    {
                        errorProvider1.SetError(txt_lim_inf, error_entero_positivo);
                        no_num = false;
                        return_value = false;
                    }
                    if (!validarNroEnteroPositivo(txt_lim_sup.Text))
                    {
                        errorProvider1.SetError(txt_lim_sup, error_entero_positivo);
                        no_num = false;
                        return_value = false;
                    }
                    if (no_num==true && Double.Parse(txt_lim_sup.Text) < Double.Parse(txt_lim_inf.Text))
                    {
                        error_entero_positivo = "Limite inferior mayor a limite superior";
                        errorProvider1.SetError(txt_lim_sup, error_entero_positivo);
                        errorProvider1.SetError(txt_lim_inf, error_entero_positivo);
                        return_value = false;
                    }
                }
            }
            return return_value;
        }

        private void habilitarTodo()
        {
            txtSemilla.Enabled = true;
            txta.Enabled = true;
            txtc.Enabled = true;
            txtm.Enabled = true;
            txtCant.Enabled = true;
            btnGenerar.Enabled = true;
        }

        private void cmbMetodo_SelectedIndexChanged(object sender, EventArgs e)
        {
            string multiplicativo = "Multiplicativo";
            string congruencial = "Congruencial Mixto";
            string nativo = "Nativo del Lenguaje";
            if (cmbMetodo.SelectedIndex!=-1 && cmbMetodo.SelectedItem.ToString().CompareTo(multiplicativo) == 0)
            {
                //Elimino seleccione Método del combo
                //cmbMetodo.Items.Remove("<Seleccione Método>");
                //Muestro la Fórmula
                lblFormula.Text = "X(i+1) = [a*Xi] (mod m)";
                habilitarTodo();
                txtc.Text = "";
                txtc.Enabled = false;
            }

            if (cmbMetodo.SelectedIndex != -1 && cmbMetodo.SelectedItem.ToString().CompareTo(congruencial) == 0)
            {
                //Elimino seleccione Método del combo
                //cmbMetodo.Items.Remove("<Seleccione Método>");
                //Muestro la Fórmula
                lblFormula.Text = "X(i+1) = [a*Xi+C] (mod m)";
                habilitarTodo();
                txtc.Text = "1013904223";
            }
            if (cmbMetodo.SelectedIndex != -1 && cmbMetodo.SelectedItem.ToString().CompareTo(nativo) == 0)
            {
                //Elimino seleccione Método del combo
                //cmbMetodo.Items.Remove("<Seleccione Método>");
                //Muestro la Fórmula
                lblFormula.Text = "";
                txtSemilla.Enabled = false;
                txta.Enabled = false;
                txtc.Enabled = false;
                txtm.Enabled = false;
                txtCant.Enabled = true;
                btnGenerar.Enabled = true;
            }
        }

        private void btnGenerar_Click_1(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            errorProvider1.Clear();
            if (validarParametros())
            {

                //aplicar la fórmula recursivamente                                
                long c;
                long.TryParse(txtc.Text, out c);
                rnd = new RandomNumber(long.Parse(txtSemilla.Text), long.Parse(txta.Text), c, long.Parse(txtm.Text), cmbMetodo.SelectedIndex);
                parametros = new Hashtable();
                //Estos parametros deberian ser tomados por pantalla pero ahora da fiaca jeje

                switch (cmbDistribucion.SelectedIndex)
                {
                    case (int) Utils.distribucion.Uniforme:
                        {
                            parametros.Add("limInf", decimal.Parse(txt_lim_inf.Text));
                            parametros.Add("limSup", decimal.Parse(txt_lim_sup.Text));
                            break;
                        }
                    case (int) Utils.distribucion.ExponencialNegativo:
                        {
                            parametros.Add("promedio", decimal.Parse(txt_lambda.Text));
                            break;
                        }
                    case (int) Utils.distribucion.Normal:
                        {
                            parametros.Add("promedio", decimal.Parse(txt_lambda.Text));
                            parametros.Add("desviacion", decimal.Parse(txt_desv.Text));
                            break;
                        }
                    case (int)Utils.distribucion.Poisson:
                        {
                            parametros.Add("promedio", decimal.Parse(txt_lambda.Text));
                            break;
                        }
                }
                dist = new DistributionController(cmbDistribucion.SelectedIndex, rnd, parametros);
                lstRandoms = dist.getNRandoms(int.Parse(txtCant.Text));
                cargarGrilla();
                btnProximo.Enabled = true;
                txt_CantInt.Enabled = true;
                btn_GenInterv.Enabled = true;
                menor = dist.getMenor();
                mayor = dist.getMayor();
                if (this.cmbDistribucion.SelectedIndex == (int)Utils.distribucion.Poisson)
                    this.txt_CantInt.Text = ( mayor - menor).ToString();
           }
            this.Cursor = Cursors.Default;
        }

        private void btnProximo_Click(object sender, EventArgs e)
        {
            if (validarParametros())
            {
                if (rnd == null)
                {
                    long c;
                    long.TryParse(txtc.Text, out c);
                    rnd = new RandomNumber(long.Parse(txtSemilla.Text), long.Parse(txta.Text), c, long.Parse(txtm.Text), cmbMetodo.SelectedIndex);
                    if (lstRandoms == null)
                    {
                        lstRandoms = new List<double>();
                    }
                }

                double nr = rnd.NextRandom();
                lstRandoms.Add(nr);
                cargarGrilla();
                txtCant.Text = ""+(Int32.Parse(txtCant.Text) + 1);
                mayor = dist.getMayor();
                menor = dist.getMenor();
                if(this.cmbDistribucion.SelectedIndex == (int)Utils.distribucion.Poisson)
                    this.txt_CantInt.Text = mayor.ToString();
            }
        }

        private void btn_GenInterv_Click_1(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            errorProvider1.Clear();
            if (validarNroEnteroPositivo(txt_CantInt.Text))
            {                
                int intervalos=int.Parse(txt_CantInt.Text);                
                decimal intervalo = dist.getIntervalo(intervalos);                
                lstIntervals = dist.getLstIntervals(intervalos);
                lstFrecuency = dist.getLstFrecuency(lstRandoms);                             
                cargarGrilla2();
                btn_GenGraf.Enabled = true;
            }
            else if (lstRandoms.Count == 0)
            {
                string error_entero_positivo = "No hay números aleatorio generados";
                errorProvider1.SetError(txt_CantInt, error_entero_positivo);
            }
            else
            {
                string error_entero_positivo = "Debe ser entero positivo";
                errorProvider1.SetError(txt_CantInt, error_entero_positivo);
            }
            this.Cursor = Cursors.Default;
        }

        private void btn_GenGraf_Click_1(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            List<decimal> labels = new List<decimal>();
            decimal intervalo=dist.getIntervalo(int.Parse(txt_CantInt.Text));
            for (int i = 0; i < lstIntervals.Count; i++)
                labels.Add(lstIntervals[i] - intervalo / 2);
            chart1.Series["Histogram"].Points.DataBindXY(labels, lstFrecuency);                        
            chart1.ChartAreas[1].AxisX.Minimum = dist.getLimiteInferior();
            chart1.ChartAreas[1].AxisX.Interval = Math.Round(double.Parse(intervalo.ToString()),2);
            chart1.ChartAreas[1].AxisX.Maximum = dist.getLimiteSuperior();
            chart1.ChartAreas["Default"].AxisX.Title = "Distribucion de frecuencia de los numeros aleatorios generados";
            chart1.ChartAreas[1].AxisX.Title = "Intervalos";
            chart1.ChartAreas[1].AxisY.Title = "Frecuencia";
            grafico = true;
            lbl_GSem.Text = txtSemilla.Text;
            lbl_Ga.Text = txta.Text;
            lbl_GC.Text = txtc.Text;
            lbl_Gm.Text = txtm.Text;
            lbl_GCantNros.Text = txtCant.Text;
            lbl_GCantInt.Text = txt_CantInt.Text;
            tabCtrl.SelectTab(1);
            this.Cursor = Cursors.Default;
        }


        private void tabCtrl_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (grafico == false && tabCtrl.SelectedIndex == 1)
            {
                tabCtrl.SelectedIndex = 0;
                MessageBox.Show("Error Primero Debe Generar el Grafico",
                "Error");
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            txt_CantInt.ResetText();
            txta.ResetText();
            txtc.ResetText();
            txtCant.ResetText();
            txtm.ResetText();
            txtSemilla.ResetText();
            txt_CantInt.Enabled=false;
            txta.Enabled=false;
            txtc.Enabled = false;
            txtCant.Enabled = false;
            txtm.Enabled = false;
            txtSemilla.Enabled = false;
            cmbMetodo.SelectedIndex = -1;
            dataGridView1.Rows.Clear();
            dataGridView2.Rows.Clear();
            tabCtrl.SelectedIndex = 0;
            grafico = false;
        //    chart_InFrec.Visible = false;
            btn_GenGraf.Enabled = false;
            btn_GenInterv.Enabled = false;            
            btnProximo.Enabled = false;
            btnGenerar.Enabled = false;
            lblFormula.Text = "Seleccione Una Distribucion";
            inicializar();
        }

        private void cmbDistribucion_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (cmbDistribucion.SelectedIndex)
            {
                case 0:
                    {
                        txt_lim_sup.Enabled = true;
                        txt_lim_inf.Enabled = true;
                        txt_lambda.Enabled = false;
                        txt_desv.Enabled = false;
                        lblFormula.Text = "UNIFORME";
                        reset_textbox();
                        break;
                    }
                case 1:
                    {
                        txt_lambda.Enabled = true; txt_lim_sup.Enabled = false;
                        txt_lim_inf.Enabled = false;
                        txt_desv.Enabled = false;
                        lblFormula.Text = "EXP NEGATIVA";
                        reset_textbox();
                        break;
                    }
                case 2:
                    {
                        txt_desv.Enabled = true;
                        txt_lambda.Enabled = true; txt_lim_sup.Enabled = false;
                        txt_lim_inf.Enabled = false;
                        lblFormula.Text = "NORMAL";
                        reset_textbox();
                        break;
                    }
                case 3:
                    {
                        txt_lambda.Enabled = true; txt_lim_sup.Enabled = false;
                        txt_lim_inf.Enabled = false;
                        txt_desv.Enabled = false;
                        lblFormula.Text = "POISSON";
                        reset_textbox();
                        break;
                    }
                default:
                    {
                        txt_lambda.Enabled = false;
                        txt_lim_sup.Enabled = false;
                        txt_lim_inf.Enabled = false;
                        txt_desv.Enabled = false;
                        reset_textbox();
                        break;
                    }
            }
        }
        private void reset_textbox() {
            txt_lambda.ResetText();
            txt_desv.ResetText();
            txt_lim_sup.ResetText();
            txt_lim_inf.ResetText();
        }
    }
}
